Skip to content

Avoid mid-word splits in replace text transform - #2050

Merged
toubatbrian merged 2 commits into
mainfrom
rosebud-scored-convert
Jul 17, 2026
Merged

Avoid mid-word splits in replace text transform#2050
toubatbrian merged 2 commits into
mainfrom
rosebud-scored-convert

Conversation

@rosetta-livekit-bot

@rosetta-livekit-bot rosetta-livekit-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Ports livekit/agents#6439 to agents-js by changing textTransforms.replace to retain only unresolved source text that is a trailing replacement-key prefix. Ordinary unmatched text emits immediately without transform-created mid-word splits.

The JS adaptation also fixes two source-inherited defects required by the stated single-pass contract:

  • Unicode case-insensitive regex equivalents now resolve to their originating replacement instead of emitting undefined.
  • Replacement output is never retained and reprocessed with a later source chunk, preventing cross-chunk cascades.

Source diff coverage

Coverage classification
Source file Classification Target file Notes
livekit-agents/livekit/agents/voice/transcription/text_transforms.py Ported with safety corrections agents/src/voice/transcription/text_transforms.ts Preserves longest-key-first stable matching and trailing source-prefix holdback. Corrects Unicode lookup and transformed-output provenance defects also present in Python #6439.
tests/test_transcription_filter.py Ported and expanded agents/src/voice/transcription/text_transforms.test.ts Covers arbitrary chunk topology, Unicode equivalents, non-cascading output, prefix completion/rejection, overlaps, UTF-16 boundaries, whitespace, EOF, and source errors.

The equivalent Unicode and replacement-provenance corrections should be applied upstream in Python.

Verification

  • pnpm exec vitest run agents/src/voice/transcription/text_transforms.test.ts — 23 passed.
  • pnpm --filter @livekit/agents typecheck.
  • pnpm --filter @livekit/agents build.
  • pnpm --filter @livekit/agents lint — exits 0 with existing warnings.
  • pnpm format:check.
  • pnpm build — 38/38 tasks successful.
  • API Extractor remains blocked by its pre-existing inability to parse the generated export * as ___ syntax; this implementation/test-only repair changes no API surface.

Cue voice E2E

Verified exact commit 9a7e1e7844c58a0f255cd941490f12c087c00688 in fresh Cue voice mode through the actual session ttsTextTransforms path, with a transparent transformed-input probe forwarding to real Cartesia TTS.

  • Session: sid_a38b0f06a84d.
  • Scenario 1: source ['you connect.'] produced exactly ['you connect.'].
  • Scenario 2: source ['visit Live', 'Kit now'] produced exactly ['visit ', 'Lyve Kit now'].
  • Scenario 3: source ['AſB'] produced exactly ['AessB'], never undefined.
  • Predicate required persisted exact-head source/transformed chunk arrays before the assistant commit; it did not rely on audio or assistant claims.
  • Result: resolved, exit code 0, with real Cartesia usage, completed speech, and no framework error event.
  • Artifacts: inspected events.jsonl, command result JSON, three per-command WAVs, and the session WAV. Both channels contain non-zero audio.

Ported from livekit/agents#6439

Original PR description

replace held back a fixed max(len(key)) - 1 trailing characters on every chunk to catch keys split across streaming boundaries, so ordinary words were emitted split mid-word (e.g. "connect." arrived as "conne" + "ct.").

It now buffers only a trailing run that could still start a replacement key and forwards the rest immediately. Substitution uses a single compiled alternation, which also avoids cascading replacements and prefers the longest match on overlapping keys.

@rosetta-livekit-bot
rosetta-livekit-bot Bot requested a review from a team as a code owner July 17, 2026 05:28
@changeset-bot

changeset-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 9a7e1e7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 37 packages
Name Type
@livekit/agents Patch
@livekit/agents-plugin-anam Patch
@livekit/agents-plugin-anthropic Patch
@livekit/agents-plugin-assemblyai Patch
@livekit/agents-plugin-azure Patch
@livekit/agents-plugin-baseten Patch
@livekit/agents-plugin-bey Patch
@livekit/agents-plugin-cartesia Patch
@livekit/agents-plugin-cerebras Patch
@livekit/agents-plugin-deepgram Patch
@livekit/agents-plugin-did Patch
@livekit/agents-plugin-elevenlabs Patch
@livekit/agents-plugin-fishaudio Patch
@livekit/agents-plugin-google Patch
@livekit/agents-plugin-hedra Patch
@livekit/agents-plugin-hume Patch
@livekit/agents-plugin-inworld Patch
@livekit/agents-plugin-lemonslice Patch
@livekit/agents-plugin-liveavatar Patch
@livekit/agents-plugin-livekit Patch
@livekit/agents-plugin-minimax Patch
@livekit/agents-plugin-mistral Patch
@livekit/agents-plugin-mistralai Patch
@livekit/agents-plugin-neuphonic Patch
@livekit/agents-plugin-openai Patch
@livekit/agents-plugin-perplexity Patch
@livekit/agents-plugin-phonic Patch
@livekit/agents-plugin-resemble Patch
@livekit/agents-plugin-rime Patch
@livekit/agents-plugin-runway Patch
@livekit/agents-plugin-sarvam Patch
@livekit/agents-plugin-silero Patch
@livekit/agents-plugin-soniox Patch
@livekit/agents-plugin-tavus Patch
@livekit/agents-plugins-test Patch
@livekit/agents-plugin-trugen Patch
@livekit/agents-plugin-xai Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@rosetta-livekit-bot
rosetta-livekit-bot Bot requested a review from longcw July 17, 2026 05:28

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

Resolve Unicode case-equivalent matches by their originating entry and keep transformed output out of source prefix holdback so later chunks cannot cascade.

Co-authored-by: Cursor <cursoragent@cursor.com>
@toubatbrian
toubatbrian merged commit 13a191c into main Jul 17, 2026
9 checks passed
@toubatbrian
toubatbrian deleted the rosebud-scored-convert branch July 17, 2026 19:34
@github-actions github-actions Bot mentioned this pull request Jul 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant